#include <iostream>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <unistd.h>

#define Creater 1
#define User 2
const char *pathname = "/home/zyq/mydir/dir/Shm";
int proj_id = 0x666;

class Shm
{
private:
    key_t GetComkey()
    {
        key_t key = ftok(_pathname, proj_id);
        if (key < 0)
        {
            perror("ftok");
            return -1;
        }
        return key;
    }
    int GetShmid(key_t key, int size, int flag)
    {
        int shmid = shmget(_key, size, flag);
        if (shmid < 0)
            perror("shmget");
        return shmid;
    }

    void AttachShm()
    {
        _addrshm = shmat(_shmid, nullptr, 0);
        if (_addrshm == nullptr)
        {
            perror("shmat");
        }
    }

    void DetachShm()
    {
        if (_addrshm != nullptr)
        {
            int n = shmdt(_addrshm);
            if (n < 0)
                perror("shmdt");
        }
    }

public:
    Shm(const char *pathname, int proj_id, int who)
        : _pathname(pathname), _proj_id(proj_id), _who(who), _addrshm(nullptr)
    {
        _key = GetComkey();
        if (who == Creater)
        {
            GetCreatershmid();
        }
        else
        {
            GetUsershmid();
        }
        //将共享内存连接到进程地址空间
        AttachShm();
        std::cout << "_key:" << _key << std::endl;
        std::cout << "_shmid:" << _shmid << std::endl;
    }
    ~Shm()
    {
        //删除进程地址空间
        shmctl(_shmid,IPC_RMID,nullptr);
        //将共享内存脱离进程地址空间
        DetachShm();
    }

    bool GetCreatershmid()
    {
        _shmid = GetShmid(_key, 4096, IPC_CREAT | IPC_EXCL|0666 );
        if (_shmid < 0)
            return false;
        else
        {
            std::cout << "Create shm done!" << std::endl;
            return true;
        }
    }

    bool GetUsershmid()
    {
        _shmid = GetShmid(_key, 4096, IPC_CREAT|0666);
        if (_shmid < 0)
            return false;
        else
        {
            std::cout << "Get shm done!" << std::endl;
            return true;
        }
    }

    void* Addr()
    {
        return _addrshm;
    }
private:
    key_t _key;
    int _shmid;

    const char *_pathname;
    int _proj_id;
    int _who;
    void *_addrshm;
};
